package tasks 
{
	import app.AppModel;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import furnitures.FurnitureFace;
	import furnitures.FurnitureModel;
	import furnitures.parts.FaceBox;
	import furnitures.parts.Foots;
	import furnitures.parts.Handle;
	import gui.PositionInfo;
	/**
	 * ...
	 * @author Dmitriy Gaiduk
	 */
	public class LoadFurnitures extends BaseXmlLoadTask
	{
		private var _model:AppModel;
		
		public function LoadFurnitures(xmlFile:String, model:AppModel) 
		{
			super(xmlFile);
			_model = model;
		}
		
		override protected function onXMLReaded(xml:XML):void 
		{
			//var arrRegExp:RegExp = /\[\d,\d\]/;
			var xmlList:XMLList;
			var heightDefault:Number = 72;
			var widthDefault:Number = 40;
			var depthDefault:Number = 570;
			
			try
			{
				xmlList = xml.item;
				var count:int = xmlList.length();
				for (var i:int = 0; i < count; i++)
				{
					var furnID:String = xmlList[i].attribute("id");
					if (furnID.length == 0)
					{
						handleError("Furniture ID not found! Item: " + i.toString());
						continue;
					}
					
					
					
					var furn:FurnitureModel = new FurnitureModel();
					
					if (_model.furnituresDict[furnID] != null) {
						log("!!!!!!!!!!!! id exist: " + furnID);
					}
					
					_model.furnituresDict[furnID] = furn;
					
					var itemType:String = xmlList[i].attribute("type");
					if (itemType.length > 0)
					{
						furn.itemType = itemType;
					}
					
					furn.furnitureHeight = getNumberFromStr(xmlList[i].attribute("height"), heightDefault, 
															"Furniture height is NaN: " + i.toString(),true);
					furn.furnitureWidth = getNumberFromStr(xmlList[i].attribute("width"), widthDefault, 
															"Furniture width is NaN: " + i.toString(), true);
					furn.furnitureDepth = getNumberFromStr(xmlList[i].attribute("depth"), depthDefault, 
															"Furniture depth is NaN: " + i.toString(), true);
					
					//read shape
					//trace("shape " + xmlList[i].elements("shape").length());
					furn.shapePoints = xmlList[i].elements("shape").length() > 0?
									getPointsFromString(xmlList[i].shape[0].attribute("points")) : null;
					if (furn.shapePoints != null)
					{
						var shapeSide:String = xmlList[i].shape[0].attribute("side");
						if (shapeSide.length != 0)
						{
							furn.shapePointsSide = shapeSide;
						}
					}
					// read curve point
					if (xmlList[i].elements("anchorCurve").length() > 0)
					{
						furn.faceAnchorCurve = new Point();
						furn.faceAnchorCurve.x = 
							getNumberFromStr(xmlList[i].elements("anchorCurve")[0].attribute("x"), 0,
														"wrong curve x: " + furnID);
						furn.faceAnchorCurve.y = 
							getNumberFromStr(xmlList[i].elements("anchorCurve")[0].attribute("y"), 0,
														"wrong curve x: " + furnID);
						
					}
					
					// read shelves
					if (xmlList[i].elements("shelves").length() > 0)
					{
						var shelves:Array = getNumberArrayFromString(xmlList[i].elements("shelves")[0].attribute("pos"));
						if (shelves != null || shelves.length != 0) {
							furn.shelves = new Vector.<Number>();
							for (var j:int = 0 ; j < shelves.length; j++) {
								furn.shelves.push(shelves[j]);
							}
						}else {
							log("wrong shelves, file: " + _xmlPath);
						}
						
						if (xmlList[i].elements("shelves")[0].attribute("force").length() > 0) {
							furn.forceShelves = true;
						}else {
							furn.forceShelves = false;
						}
					}
					
					// double sided?
					if (xmlList[i].attribute("inside").length() > 0) {
						furn.doubleSided = true;
					}else {
						furn.doubleSided = false;
					}
					//read height, posY
					furn.positionY = getNumberFromStr(xmlList[i].attribute("posY"), 0, 
															"Furniture posY is NaN: " + i.toString(), true);
					furn.hasTabletop = xmlList[i].attribute("tabletop") == "1" ? true : false;
					
					// title
					furn.title = xmlList[i].attribute("title");
					
					//read faces
					var faces:XMLList = xmlList[i].face;
					readFaces(xmlList[i].face, furn);
					
					//read foots
					var foots:XMLList = xmlList[i].foots;
					if (foots.length() > 0)
					{
						furn.foots = new Foots();
						readFoots(foots, furn);
					}
				}
			}
			catch(err:Error)
			{
				handleError("Error while read furniture XML: " + err.errorID + "; " + err.name + "; "  + err.message);
				_model.inited = false;
				complete(false);
				return;
			}
			complete(true);
		}
		
		private function readFoots(foots:XMLList, furn:FurnitureModel):void 
		{
			try
			{
				var footsCount:int = foots.length();
				if (footsCount == 0)
				{
					return;
				}
				
				var pointsArr:Array = getPointsFromString(foots[0].attribute("positions"));
				if (pointsArr == null)
				{
					return;
				}
				
				for (var i:int = 0; i < pointsArr.length; i++)
				{
					furn.foots.addPositionXY(pointsArr[i][0], pointsArr[i][1]);
				}
				
				var decorShapeStr:String = foots[0].attribute("decor");
				if(decorShapeStr.length > 0 ){
					var decorPoints:Array = getPointsFromString(foots[0].attribute("decor"));
					furn.foots.decorPoints = decorPoints;
				}
			}
			catch(err:Error)
			{
				handleError("Error while read foots XML: " + err.errorID + "; " + err.name + "; "  + err.message);
				return;
			}
		}
		
		private function readFaces(facesList:XMLList, furniture:FurnitureModel):void
		{
			try
			{
				var facesCount:int = facesList.length();
				for (var j:int = 0;  j < facesCount; j++)
				{
					var faceIndex:Number = getNumberFromStr(facesList[j].attribute("index"), 0, 
									"Furniture face index is NaN");
					var faceModel:FurnitureFace = new FurnitureFace(faceIndex);
					// read doors
					readBoxes(facesList[j].door, faceModel);
					furniture.addFace(faceModel);
				}
			}
			catch(err:Error)
			{
				handleError("Error while read faces XML: " + err.errorID + "; " + err.name + "; "  + err.message);
				return;
			}
		}
		
		private function printAllFurns():void
		{
			trace("");
			trace("===============================================");
			printAllFurns();
			for (var k:Object in _model.furnituresDict) 
			{
			  var value:FurnitureModel = _model.furnituresDict[k] as FurnitureModel;
			  var key:Object = k;
			  if (value != null)
			  {
				  trace("Furniture: " + key);
				  printFurniture(value);
				  trace("==========================");
			   }
			}
		}
		
		private function printFurniture(furn:FurnitureModel):void
		{
			trace("Title: " + furn.title);
			trace("Height: " + furn.furnitureHeight);
			trace("PositionY: " + furn.positionY);
			trace("Has Tabletop: " + furn.hasTabletop);
			if (furn.faces != null)
			{
				for (var i:int = 0; i < furn.faces.length; i++ )
				{
					trace(" Face index: " + furn.faces[i].index);
					if (furn.faces[i].doors != null)
					{
						for (var j:int = 0; j < furn.faces[i].doors.length; j++ )
						{
							trace("  Door: " +  furn.faces[i].doors[j].positionUV.x + "," + 
										furn.faces[i].doors[j].positionUV.y +
									"; " +  furn.faces[i].doors[j].posRD.x + ", " +  furn.faces[i].doors[j].posRD.y);
						}
					}else
					{
						trace("  Door <empty>");
					}
				}
			}else
			{
				trace(" Face <empty>");
			}
		}
		
		private function readBoxes(doorXMLList:XMLList, face:FurnitureFace):void
		{
			var count:int = doorXMLList.length();
			for (var i:int = 0; i < count; i++ )
			{
				var posUL:Array = getPairNumber(doorXMLList[i].attribute("ul"));
				var posRD:Array = getPairNumber(doorXMLList[i].attribute("rd"));
				if ((posUL != null) && (posRD != null))
				{
					var box:FaceBox = new FaceBox(new Point(posUL[0], posUL[1]), new Point(posRD[0], posRD[1]));
					box.glass = doorXMLList[i].attribute("glass").length() > 0? 
								getNumberArrayFromString(doorXMLList[i].attribute("glass")):null;
					box.sizeType = doorXMLList[i].attribute("size");
					face.addDoor(box);
					// check allow extra
					if (doorXMLList[i].attribute("noextra").length() > 0) {
						box.allowExtra = false;
					}else {
						box.allowExtra = true;
					}
					
					if (doorXMLList[i].elements("lines").length() > 0)
					{
							box.lines = 
							getPointsFromString(doorXMLList[i].elements("lines")[0].attribute("points"));
					}
					
					if (doorXMLList[i].elements("shape").length() > 0)
					{
							box.doorShape = 
							getPointsFromString(doorXMLList[i].elements("shape")[0].attribute("points"));
					}
					// read handles
					if (doorXMLList[i].elements("handle").length() > 0)
					{
						var handle:Handle;
						var handleCount:int = doorXMLList[i].elements("handle").length();
						var handleList:XMLList = doorXMLList[i].elements("handle");
						for (var k:int = 0; k < handleCount; k++)
						{
							handle = readDoorHandle(handleList[k]);
							box.addHandle(handle);
						}
					}
					box.type = getBoxType(doorXMLList[i].attribute("type"));
					
					
				}else
				{
					handleError("door pos is uncorrect");
				}
			}
		}
		
		private function getBoxType(type:String):String
		{
			var typeToReturn:String = FaceBox.TYPE_FURNITURE;
			
			switch(type) {
				case "tech":
						typeToReturn = FaceBox.TYPE_TECH;
					break;
				default:
						typeToReturn = FaceBox.TYPE_FURNITURE;
					break;
				
			}
			
			return typeToReturn;
		}
		
		private function readDoorHandle(handleXML:XML):Handle
		{
			var posInfo:PositionInfo = getPosition(handleXML);
			var handleStr:String = handleXML.attribute("type");
			var handleType:int = Handle.HANDLE_VERTICAL;
			switch(handleStr)
			{
				case "v":
						handleType = Handle.HANDLE_VERTICAL;
					break;
				case "h":
						handleType = Handle.HANDLE_HORIZONTAL;
					break;
			}
			
			return new Handle(posInfo, handleType);
		}
		
		
		
		private function getPosition(xmlNode:XML):PositionInfo
		{
			var pos:PositionInfo = new PositionInfo();
			try
			{
				pos.posX = getNumberFromStr(xmlNode.attribute("x"), 0, "wrong number position x", true);
				pos.posY = getNumberFromStr(xmlNode.attribute("y"), 0, "wrong number position y", true);
				pos.leftPadding = getNumberFromStr(xmlNode.attribute("leftPadding"), 
												0, "wrong number position leftPadding", true);
												
				pos.rightPadding = getNumberFromStr(xmlNode.attribute("rightPadding"), 
												0, "wrong number position rightPadding", true);
												
				pos.topPadding = getNumberFromStr(xmlNode.attribute("topPadding"), 
												0, "wrong number position topPadding", true);
												
				pos.bottomPadding = getNumberFromStr(xmlNode.attribute("bottomPadding"), 
												0, "wrong number position bottomPadding", true);
				pos.align = getAlignXML(xmlNode);														
			}
			catch(err:Error)
			{
				handleError("Error read position info: " + err.errorID + "; " + err.name + "; "  + err.message);
				return null;
			}
			return pos;
		}
		
		private function getAlign(alignXml:String):int 
		{
			var align:int = PositionInfo.ALIGN_NONE;
			
			switch(alignXml)
			{
				case "top":
					align = PositionInfo.ALIGN_TOP;
					break;
				case "bottom":
					align = PositionInfo.ALIGN_BOTTOM;
					break;
				case "centrx":
					align = PositionInfo.ALIGN_CENTR_X;
					break;
				case "centry":
					align = PositionInfo.ALIGN_CENTR_Y;
					break;
				case "left":
					align = PositionInfo.ALIGN_LEFT;
					break;
				case "right":
					align = PositionInfo.ALIGN_RIGHT;
					break;
			}
			return align;
		}
		
		private function getAlignXML(alignXml:XML):int 
		{
			var align:int = PositionInfo.ALIGN_NONE;
			if (alignXml.attribute("centrx").length() > 0)
			{
				align = align | PositionInfo.ALIGN_CENTR_X;
			}
			if (alignXml.attribute("centry").length() > 0)
			{
				align = align | PositionInfo.ALIGN_CENTR_Y;
			}
			if (alignXml.attribute("right").length() > 0)
			{
				align = align | PositionInfo.ALIGN_RIGHT;
			}
			if (alignXml.attribute("left").length() > 0)
			{
				align = align | PositionInfo.ALIGN_LEFT;
			}
			if (alignXml.attribute("top").length() > 0)
			{
				align = align | PositionInfo.ALIGN_TOP;
			}
			if (alignXml.attribute("bottom").length() > 0)
			{
				align = align | PositionInfo.ALIGN_BOTTOM;
			}
			return align;
		}
		
		private function getPairNumber(nums:String):Array
		{
			var numberPairRegExp:RegExp = /\s*[0-9][0-9]*\.?[0-9]*\s*\,\s*[0-9][0-9]*\.?[0-9]*\s*/g;
			var numberRegExp:RegExp = /[0-9][0-9]*\.?[0-9]*/g;
			var arrMatch:Array = nums.match(numberPairRegExp);
			var coords:Array = [];
			if (arrMatch != null)
			{
				if (arrMatch.length == 1)
				{
					var arrPartStr:String = arrMatch[0];
					var coordsArr:Array = arrPartStr.match(numberRegExp);
					for (var j:int = 0; j < coordsArr.length; j++ )
					{
						var coord:Number = getNumberFromStr(coordsArr[j], 0, "pair coord is NaN");
						coords.push(coord);
					}
				}else
				{
					handleError("pair coords: error count mathes: " + arrMatch.length);
				}
				
			}else
			{
				handleError("pair coords: no mathes");
			}
			
			if (coords.length == 2)
			{
				return coords;
			}else
			{
				return null;
			}
		}
		
		private function getNumberArrayFromString(pointsStr:String):Array
		{
			//var arrRegExp:RegExp = /(\s*[0-9][0-9]*\.?[0-9]*\s*\,\s*){0,}\s*[0-9][0-9]*\.?[0-9]*\s*/g;
			var numberRegExp:RegExp = /[0-9][0-9]*\.?[0-9]*/g;
			var arrMatch:Array = pointsStr.match(numberRegExp);
			var numbersArr:Array = [];
			if (arrMatch != null)
			{
				var num:Number;
				numbersArr = [];
				for (var i:int = 0; i < arrMatch.length; i++ )
				{
					num = Number(arrMatch[i]);
					if (!isNaN(num))
					{
						numbersArr.push(num);
					}else
					{
						handleError("NaN getArrayFromString: " + pointsStr);
					}
					
				}
			}else
			{
				handleError("no mathes");
			}
			return numbersArr;
		}
		
		/**
		 * 
		 * @param	points [ [x1, y1, x2, y2], [x1, y1, x2, y2, .. xN, yN] ]
		 * @return
		 */
		private function getPointsFromString(points:String):Array
		{
			if ((points == null) || (points.length == 0))
			{
				return null;
			}
			var arrRegExp:RegExp = /\[(\s*[0-9][0-9]*\.?[0-9]*\s*\,\s*){1,}\s*[0-9][0-9]*\.?[0-9]*\s*\]/g;
			var numberRegExp:RegExp = /[0-9][0-9]*\.?[0-9]*/g;
			var arrMatch:Array = points.match(arrRegExp);
			var shapeArr:Array = [];
			//trace("string: " + points);
			if (arrMatch != null)
			{
				for (var i:int = 0; i < arrMatch.length; i++ )
				{
					var arrPartStr:String = arrMatch[i];
					var coordsArr:Array = arrPartStr.match(numberRegExp);
					var coords:Array = [];
					for (var j:int = 0; j < coordsArr.length; j++ )
					{
						var coord:Number = Number(coordsArr[j]);
						if (isNaN(coord))
						{
							break;
							handleError("Coord is NaN");
						}
						coords.push(coord);
					}
					//if ((coords.length == 2) || (coords.length == 4))
					if (coords.length % 2 ==0) // 
					{
						shapeArr.push(coords);
					}else
					{
						log("Wrong count points: " + coords.length);
					}
				}
			}else
			{
				handleError("no mathes");
			}
			return shapeArr;
		}
		
		override protected function handleError(err:String):void 
		{
			super.handleError("Load furnitures: " + err);
		}
		
		override public function destroy():void 
		{
			_model = null; 
			super.destroy();
		}
		
	}

}